package tools.chapter25;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author Kevin
 * @date 2020/4/14 14:16
 */
public class getMin {



    public static AtomicReference<Integer> getMinPrice() throws InterruptedException {
        //创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        //创建CompletionService
        CompletionService cs = new ExecutorCompletionService(executor);
        //线程同步器
        CountDownLatch latch = new CountDownLatch(3);
        //异步向电商询价
        cs.submit(()->getPriceByS1());
        cs.submit(()->getPriceByS2());
        cs.submit(()->getpriceByS3());
        //将询问结果异步保存到数据库
        AtomicReference<Integer> m = new AtomicReference<>(Integer.MAX_VALUE);
        for (int i = 0; i < 3; i++) {
            Integer r = null;
            try {
                r = (Integer) cs.take().get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            //这里是先查询到的先保存，使用CompletionService实现；
            //也可以save放进cs.submit(()->getPriceByS1());中
            save(r);
            //先调用m.get()并跟r比较，再调用m.set()，这里存在竞态条件，线程并不安全
            //m.set(Integer.min(m.get(), r)... 这个操作也不是原子操作
            /**
            * m.set(Integer.min(m.get(), r));
            */
            //方法1：
//            for (int i=0; i<3; i++) {
//                Integer r = logIfError(()->cs.take().get()); <--已经保证先查询到的先提交
//                executor.execute(()-> save(r));   <----异步保存
//                m.getAndUpdate(v->Integer.min(v, r));   <--get set操作原子化
//            }
            //方法2：使用栅栏
            m.set(Integer.min(m.get(), r));
            latch.countDown();
        }
        //需要等待三个线程执行完毕
        latch.await();
        return m;
    }
    public static Integer getPriceByS1()  throws InterruptedException {
        Thread.sleep(100);
        return 1;
    }
    public static Integer getPriceByS2()  throws InterruptedException {
        Thread.sleep(100);
        return 2;
    }
    public static Integer getpriceByS3()  throws InterruptedException {
        Thread.sleep(100);
        return 3;
    }
    public static void save(Integer in) {}
}
